//
//  SWUploadOperation.swift
//  YiyaPuzzleDemo
//
//  Created by linhan on 16/10/22.
//  Copyright © 2016年 test. All rights reserved.
//

import Foundation

struct SWUploadResponse
{
    var localPath:String = ""
    var bookID:String = ""
    var pageID:String = ""
    var origin:Bool = false
    var url:String = ""
}

class SWUploadOperation:Operation,SWAPIComponent
{
    var successCallback:((SWUploadResponse)->Void)?
    var failCallback:(()->Void)?
    var localPath:String = ""
    var bookID:String = ""
    var pageID:String = ""
    var origin:Bool = false
    
    
    override var isExecuting: Bool{
        return _executing
    }
    
    override var isFinished: Bool{
        return _finished
    }
    
    
    private var _executing:Bool = false{
        willSet{
            willChangeValue(forKey: "isExecuting")
        }
        didSet{
            didChangeValue(forKey: "isExecuting")
        }
    }
    
    private var _finished:Bool = false{
        willSet{
            willChangeValue(forKey: "isFinished")
        }
        didSet{
            didChangeValue(forKey: "isFinished")
        }
    }
    
    private var _saveKey:String = ""
    private var _uploadToken:String = ""
    private var _url:String = ""
    private var _task:SWUploadTask
    private var _retryTimes:Int = 0
    private let MaxRetryTimes:Int = 6
    private var _uploadManager:QNUploadManager?
    
    
    init?(task:SWUploadTask)
    {
        _task = task
        super.init()
        guard let bookID = task.bookID,let pageID = task.pageID,let localPath = task.localPath, bookID != "" && pageID != "" && localPath != "" else{
            return nil
        }
        
        self.localPath = localPath
        self.bookID = bookID
        self.pageID = pageID
        origin = task.origin
        
        _uploadManager = QNUploadManager(configuration: SWImageUploader.QNUploadConfig)
    }
    
    deinit
    {
        print("DEINIT SWUploadOperation")
    }
    
    override func start()
    {
        if isCancelled
        {
            _executing = false
            _finished = true
            return
        }
        
        _executing = true
        
        uploadAndUpdate()
    }
    
    override func cancel() {
        super.cancel()
        if _executing
        {
            
        }
        //dataTask.cancel()
    }
    
    func update(_ task:SWUploadTask)
    {
        
    }
    
    private func uploadAndUpdate()
    {
        if _saveKey == "" || _uploadToken == ""
        {
            fetchUploadToken()
        }
        else if _url == ""
        {
            upload()
        }
        else
        {
            update(_url)
        }
    }
    
    //获取相关上传凭证
    private func fetchUploadToken()
    {
        let time:Int = Int(NSDate().timeIntervalSince1970)
        #if DEBUG
            let BASE_PATH:String = "test/"
        #else
            let BASE_PATH:String = ""
        #endif
        _saveKey = "\(BASE_PATH)\(time)_\(StringUtil.getUniqid(5))"
        
        let req:SWUploadTokenFetchReq = SWUploadTokenFetchReq()
        req.successCallback = {[weak self] response, cache in
            if let response = response as? SWUploadTokenFetchRsp,
                let token = response.token, token != ""{
                trace("token:", token)
                self?._uploadToken = token
                self?.uploadAndUpdate()
            }
            else
            {
                self?.uploadAndUpdateFail()
            }
        }
        req.failCallback = {[weak self] error in
            self?.uploadAndUpdateFail()
        }
        load(req)
    }
    
    private func createUploadToken() -> (token:String, saveKey:String)
    {
        let saveKey:String = "test/\(StringUtil.getUniqid(8)).jpg"
        let scope = "yiya:\(saveKey)"
        //有效期一个小时
        let deadline = Int(NSDate().timeIntervalSince1970) + 3600 * 24
        var putPolicy:[String:AnyObject] = [:]
        putPolicy["scope"] = scope as AnyObject?
        putPolicy["deadline"] = deadline as AnyObject?
        let AccessKey = "vLHbgaYj8mfvPUTpMCYLbAetXh-Cg0Fk0R_FtAN_"
        let SecretKey = "re1EvlR0FwlSv9YEYlJsHw_WRIcshxhbxilGvmRN"
        let putPolicyString = QNUrlSafeBase64.encode(JSONHelper.JSONEncode(putPolicy)) ?? ""
        let sign = CryptoOC.hmac_sha1(putPolicyString, key: SecretKey) ?? ""
        let uploadToken = "\(AccessKey):\(sign):\(putPolicyString)"
        return (token:uploadToken, saveKey:saveKey)
    }
    
    private func upload()
    {
        if let data = FileUtility.getFileFromPath(localPath)
        {
            //trace("上传:", data.count, localPath)
            let token = _uploadToken
            let saveKey = _saveKey
            
            QNUpload(data: data, saveKey: saveKey, uploadToken: token, successCallback: {[weak self] url in
                self?.uploadSuccess(url)
                }, failCallback: {[weak self] in self?.uploadAndUpdateFail()})
        }
        else
        {
            notifyFail()
        }
    }
    
    private func QNUpload(data:Data, saveKey:String, uploadToken:String, successCallback:((String)->Void)?, failCallback:(()->Void)?)
    {
        _uploadManager?.put(data, key:saveKey, token:uploadToken, complete:{ info, akey, response in
            if let key = response?["key"] as? String, key != ""
            {
                let url:String = "\(SW.Config.imageStoreBaseURL)/\(key)"
                successCallback?(url)
                trace(url)
            }else{
                failCallback?()
            }
        }, option:nil)
    }
    
    private func uploadSuccess(_ url:String)
    {
        _url = url
        update(url)
    }
    
    //更新服务端相关页面
    private func update(_ url:String)
    {
        notifySuccess(url)
    }
    
    //上传更新失败
    private func uploadAndUpdateFail()
    {
        if _retryTimes < MaxRetryTimes
        {
            _retryTimes += 1
            uploadAndUpdate()
        }
        else
        {
            notifyFail()
        }
    }
    
    private func notifySuccess(_ url:String)
    {
        var response = SWUploadResponse()
        response.bookID = bookID
        response.pageID = pageID
        response.localPath = localPath
        response.origin = origin
        response.url = url
        successCallback?(response)
        _executing = false
        _finished = true
    }
    
    private func notifyFail()
    {
        failCallback?()
        _executing = false
        _finished = true
    }
    
    
    
}
